#include "app_buffer.h"
#include <stdlib.h>
#include <string.h>
#include "thirdparty/log.c/log.h"

static pthread_mutex_t LOCK_INITIALIZER = PTHREAD_MUTEX_INITIALIZER;

int app_buffer_init(Buffer *buffer, int len)
{
    log_trace("app_buffer_init: enter");
    buffer->data = malloc(len);
    if (!buffer->data)
    {
        log_warn("Not enough memory for buffer %p", buffer);
        return -1;
    }
    buffer->total_len = len;
    buffer->start_offset = 0;
    buffer->data_len = 0;
    memcpy(&buffer->lock, &LOCK_INITIALIZER, sizeof(pthread_mutex_t));
    log_trace("app_buffer_init: leave");
    return 0;
}

int app_buffer_read(Buffer *buffer, void *buf, int buf_len)
{
    if (!buffer || !buf)
    {
        log_warn("Buffer ptr or buf ptr is NULL");
        return -1;
    }
    log_trace("Before read Buffer status: start_offset %d, data_len: %d", buffer->start_offset, buffer->data_len);
    // 确定能读多长
    pthread_mutex_lock(&buffer->lock);
    int len = buffer->data_len > buf_len ? buf_len : buffer->data_len;

    if (len == 0)
    {
        pthread_mutex_unlock(&buffer->lock);
        log_debug("Buffer data or buf len is zero");
        return 0;
    }

    // 开始读，考虑一次读还是两次读
    if (buffer->start_offset + len <= buffer->total_len)
    {
        // 一次就可以读出
        memcpy(buf, buffer->data + buffer->start_offset, len);
        buffer->start_offset += len;
    }
    else
    {
        // 分两次读
        // 第一次读的长度
        int first_read_len = buffer->total_len - buffer->start_offset;
        memcpy(buf, buffer->data + buffer->start_offset, first_read_len);
        memcpy(buf + first_read_len, buffer->data, len - first_read_len);
        buffer->start_offset = len - first_read_len;
    }
    buffer->data_len -= len;

    pthread_mutex_unlock(&buffer->lock);
    log_trace("After read Buffer status: start_offset %d, data_len: %d", buffer->start_offset, buffer->data_len);
    return len;
}

int app_buffer_write(Buffer *buffer, void *buf, int buf_len)
{
    // 能否写进去
    if (!buffer || !buf)
    {
        return -1;
    }
    log_trace("Before write Buffer status: start_offset %d, data_len: %d", buffer->start_offset, buffer->data_len);
    pthread_mutex_lock(&buffer->lock);
    if (buf_len > buffer->total_len - buffer->data_len)
    {
        pthread_mutex_unlock(&buffer->lock);
        return -1;
    }

    // 先要找到写的起点
    int write_offset = buffer->start_offset + buffer->data_len;
    if (write_offset > buffer->total_len)
    {
        write_offset -= buffer->total_len;
    }

    // 写一次还是写两次
    if (buffer->total_len - write_offset >= buf_len)
    {
        // 一次写入
        memcpy(buffer->data + write_offset, buf, buf_len);
    }
    else
    {
        // 写两次
        int first_write_len = buffer->total_len - write_offset;
        memcpy(buffer->data + write_offset, buf, first_write_len);
        memcpy(buffer->data, buf + first_write_len, buf_len - first_write_len);
    }
    buffer->data_len += buf_len;

    pthread_mutex_unlock(&buffer->lock);
    log_trace("After write Buffer status: start_offset %d, data_len: %d", buffer->start_offset, buffer->data_len);
    return 0;
}

void app_buffer_free(Buffer *buffer)
{
    if (buffer->data)
    {
        free(buffer->data);
        buffer->data = NULL;
    }
    buffer->total_len = 0;
    buffer->data_len = 0;
    buffer->start_offset = 0;
}
